Skip to main content

ClamAV Antivirus

**** ClamAV Antivirus for WordPress VPS – Learning Material (Server-Side Security)

ClamAV is a server-level antivirus designed to detect and remove malware, webshells, PHP backdoors, infected uploads, and trojanized plugins/themes inside a WordPress VPS. It is open-source, lightweight, and trusted for Linux server security. This module teaches you how to install, configure, scan, automate, and harden WordPress environments using ClamAV via CLI-only workflow.

Learning Objectives​

After completing this module, you will be able to:

  • Understand ClamAV antivirus behavior on Linux VPS
  • Scan and quarantine malware on WordPress directories
  • Configure real-time on-demand protection
  • Detect PHP malware patterns in plugins/themes
  • Automate malware scanning using cron
  • Integrate ClamAV with WordPress security stack
  • Clean infected files safely without downtime

5W+1H Overview​

QuestionAnswer
WhatClamAV = Linux antivirus engine
WhyDetect malware in WordPress uploads, plugins, themes
WhereRuns directly on server filesystem
WhenDuring security audits, malware cleanup
WhoServer admins, DevOps, secure WP owners
HowCLI commands + cron automation

Key Commands Overview​

CommandDescription
clamscanOn-demand scan
freshclamSignature updates
clamdDaemon for faster scanning
clamscan -rRecursive scan
clamscan --moveMove infected to quarantine
clamscan --removeDelete infected files

Installation – Ubuntu 22/24 LTS​

sudo apt update
sudo apt install clamav clamav-daemon -y
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam

Verify:

clamscan --version

WordPress Directory Scan​

Basic scan for malware under a WordPress site:

clamscan -r /home/user/public_html

Scan all web users:

clamscan -r /home --include-dir="public_html"

Scan only risky PHP files:

clamscan -r --include="\.php$" /home/user/public_html

Quarantine and Cleanup Strategy​

Safer than deleting infected files immediately.

Create quarantine directory​

mkdir /virus
chmod 700 /virus

Move infected files to quarantine​

clamscan -r /home/user/public_html --move=/virus

Remove only confirmed malware​

clamscan -r /home/user/public_html --remove

Real-Time Daemon Mode (clamd)​

Better performance for large servers:

sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon

Scan using daemon:

clamdscan -r /home/user/public_html

Excluding Safe Directories​

clamscan -r /home/user/public_html --exclude-dir="cache"

clamscan -r /home/user/public_html --exclude-dir="wp-content/cache"

Cron Automation for Daily Scanning​

crontab -e

Add:

0 3 * * * clamscan -r /home/user/public_html --move=/virus --log=/var/log/clamwp.log

Scan by File Type – High Risk Extensions​

clamscan -r --include="\.php$|\.js$|\.ico$" /home/user/public_html

Detect Obfuscated Malware​

grep -R --include=*.php "base64_decode" /home/user/public_html
grep -R --include=*.php "eval(" /home/user/public_html
grep -R --include=*.php "gzinflate" /home/user/public_html

Custom Malware Signatures (Optional Advanced)​

Create file:

/var/lib/clamav/custom.ndb

Example signature line:

BadShell:0:*:3c3f706870406576616c28245f504f53545b

Reload:

freshclam

Logs & Reports​

Latest ClamAV log:

tail -n 50 /var/log/clamav/clamav.log

Log to custom file:

clamscan -r /home/user/public_html --log=/virus/scan.log

Malware Cleanup Workflow (WordPress Safe)​

StepAction
1Put site under maintenance
2Full backup (files + DB)
3Scan with ClamAV
4Quarantine infected
5Reinstall core WP files
6Replace plugins/themes
7Clean uploads folder
8Change all passwords

Best Practice Configuration​

  • Do not auto delete malware without review
  • Always quarantine first
  • Exclude cache and backup folders to speed scan
  • Enable cron-based scheduled scans
  • Scan uploads folder weekly
  • Combine with Fail2Ban + UFW + WP hardening
  • Block PHP in /uploads/

WordPress Security Stack Integration​

LayerTool
FirewallUFW
Brute Force DefenseFail2Ban
AntivirusClamAV
App FirewallCloudflare WAF
WP Malware ScanWordfence CLI
Integrity Checkerwp-cli checksum

Practical Commands Cheat Sheet​

PurposeCommand
Test scanclamscan --infected --remove
Scan siteclamscan -r /home/user/public_html
Quarantine--move=/virus
Log scan--log=/virus/log.txt
Update DBfreshclam
Fast scanclamdscan
PHP only--include="\.php$"

Troubleshooting​

IssueSolution
Slow scanUse clamd
Can't update DBStop service systemctl stop clamav-freshclam first
Too many false positivesUse --move not --remove
Exclude cache foldersUse --exclude-dir
Permission deniedUse sudo

Optimize Performance for Large WordPress Servers​

ClamAV can be slow by default when scanning large servers with many PHP files. Optimize it.

19.1 Increase Max File Size & Scan Limits​

Edit config:

sudo nano /etc/clamav/clamd.conf

Enable or adjust:

MaxFileSize 200M
MaxScanSize 400M
MaxRecursion 20

19.2 Enable Multi-Core Scanning​

ClamAV doesn’t support threading by default. Use parallel scan:

find /home -type d -name public_html -print0 | xargs -0 -P 4 -I {} clamscan -ri {}

Uses 4 parallel processes to speed up scanning.

19.3 Exclude Cache & TMP Folders (Speed Boost)​

clamscan -r /home \
--exclude-dir="wp-content/cache" \
--exclude-dir="wp-content/uploads/cache" \
--exclude-dir="tmp" \
--exclude-dir="backup"

30–60% faster scans.

Targeted Malware Detection for WordPress​

20.1 Scan Only Uploads Folder (high-risk)​

clamscan -r /home/*/public_html/wp-content/uploads --move=/virus

20.2 Scan Only PHP Files​

clamscan -r /home --include="\.php$" --move=/virus

20.3 Scan Modified Files in Last 2 Days​

find /home -type f -mtime -2 -print0 | xargs -0 clamscan --move=/virus

Detect Backdoors, Webshells & PHP Malware​

21.1 Manual Search (Ready to Use)​

grep -R --include=*.php "base64_decode" /home
grep -R --include=*.php "eval(" /home
grep -R --include=*.php "shell_exec" /home
grep -R --include=*.php "passthru" /home
grep -R --include=*.php "assert(" /home
grep -R --include=*.php "gzinflate" /home
grep -R --include=*.php "str_rot13" /home

These functions often used in backdoors.

Recommended focus:

  • /wp-content/uploads/
  • /wp-content/plugins/
  • /wp-content/themes/

Create Quarantine & Audit Workflow​

22.1 Quarantine Folder (Safe Actions)​

mkdir -p /virus
chmod 700 /virus

22.2 Log Infected Files​

clamscan -r /home --log=/var/log/clamav-wordpress.log --move=/virus

22.3 See Reported Malware​

grep "FOUND" /var/log/clamav-wordpress.log

Auto-Cleanup Script (Safe)​

Create script:

nano /usr/local/bin/clamwp-clean.sh

Add:

#!/bin/bash
SCAN_DIR="/home"
QUAR_DIR="/virus"
LOG="/var/log/clamwp.log"
clamscan -ri $SCAN_DIR --move=$QUAR_DIR --log=$LOG

Run:

chmod +x /usr/local/bin/clamwp-clean.sh

Automate Daily Security Scan (Cron)​

Run daily at 2 AM:

crontab -e

Add:

0 2 * * * /usr/local/bin/clamwp-clean.sh >/dev/null 2>&1

Email Infection Alerts​

Install mail library:

sudo apt install mailutils -y

Edit script to send alert:

if grep -q "FOUND" /var/log/clamwp.log; then
mail -s " ClamAV Alert - Malware Found" admin@yourdomain.com < /var/log/clamwp.log
fi

Schedule High-Security Scanning​

ScheduleScopeCommand
DailyUploads folderclamscan -r wp-content/uploads
WeeklyFull WordPressclamscan -r /home
MonthlyEntire VPSclamscan -r /

ClamAV + Wordfence CLI + Malware Double Scan​

Combine detection power:

clamscan -r /home --move=/virus
wordfence scan

Detects encrypted malware + PHP webshells.

Block PHP in Uploads (Critical Layer Defense)​

nano /home/user/public_html/wp-content/uploads/.htaccess

Add:

<Files *.php>
deny from all
</Files>

Real-Time File Monitoring (Optional)​

Detect sudden malware upload:

apt install inotify-tools -y
inotifywait -r -m /home/*/public_html/wp-content/uploads

Hardening Summary (Best Practice)​

ActionStatus
Daily malware scans
Quarantine enabled
Email alerts
Uploads folder secured
PHP disabled in uploads
Wordfence CLI paired
Backdoor search scripts
Cron automation

ClamAV Bash Malware Cleaner Toolkit — Part 3 (Safe Mode: B1)

Quick intro: this toolkit is CLI-first, safe-mode only — it scans, quarantines, logs, and alerts but never deletes. Designed to drop into a WordPress VPS (OpenLiteSpeed or any Linux web server). One-shot delivery, full scripts, cron entries, log handling, testing, and troubleshooting included.

Design goals (what this toolkit does)​

  1. Scan WordPress sites (per-user public_html) for malware and suspicious file types.
  2. Move infected files to a secure quarantine (/var/quarantine/clamav) — never delete.
  3. Produce compact daily logs and an alert email if anything is found.
  4. Support incremental (recent files) and full scans.
  5. Be safe for production: always require manual review of quarantined files.
  6. Be easy to extend and review (single script, small helpers).

Requirements / Install (Ubuntu 22/24 LTS)​

sudo apt update
sudo apt install -y clamav clamav-daemon inotify-tools mailutils psmisc
# stop freshclam while first DB update if necessary
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl enable --now clamav-freshclam clamav-daemon

Verify:

clamscan --version
clamdscan --version
systemctl status clamav-daemon

Expected (example) snippet:

ClamAV 1.0.0/26000/Thu Oct 23 02:00:00 2025

Files & layout (what I’ll create)​

  • /usr/local/bin/clamwp-scan.sh — main safe-mode scanner (executable).
  • /usr/local/bin/clamwp-utils.sh — small helper functions (optional).
  • /var/log/clamwp/ — logs (rotated by script).
  • /var/quarantine/clamav/ — quarantined files (700 perms).
  • Cron entries to run daily + weekly incremental.

Main script — clamwp-scan.sh​

Create the file and make executable:

sudo tee /usr/local/bin/clamwp-scan.sh > /dev/null &lt;&lt;'EOF'
#!/usr/bin/env bash
# ClamAV WordPress Safe Scan Toolkit - Safe Mode (B1)
# - Scans specified roots
# - Moves infected files to quarantine (never deletes)
# - Produces logs and simple email alerts
# - Safe defaults; review quarantined files manually

set -euo pipefail
IFS=$'\n\t'

# === CONFIG ===
SCAN_ROOTS=(/home) # array of directories to probe for public_html
QUAR_DIR="/var/quarantine/clamav" # quarantine directory (must exist)
LOG_DIR="/var/log/clamwp" # log directory
LOG_FILE="${LOG_DIR}/clamwp-$(date +%F).log"
FRESHCLAM_ON_START=true # update signatures before scan
PARALLEL_PROCS=3 # xargs -P value for parallel scanning of sites
EMAIL_ALERT="admin@yourdomain.example" # set to admin email or leave empty to disable email
MAX_AGE_DAYS=2 # used by 'recent' mode
EXCLUDE_DIRS=("*/wp-content/cache/*" "*/node_modules/*" "*/tmp/*" "*/backup/*")
# === END CONFIG ===

mkdir -p "$QUAR_DIR" "$LOG_DIR"
chmod 700 "$QUAR_DIR"
touch "$LOG_FILE"
chmod 600 "$LOG_FILE"

timestamp(){ date "+%Y-%m-%d %H:%M:%S"; }

log(){ printf "%s %s\n" "$(timestamp)" "$*" >> "$LOG_FILE"; }

# update DB
if [ "${FRESHCLAM_ON_START}" = true ]; then
log "Starting freshclam update"
if ! freshclam >> "$LOG_FILE" 2>&1; then
log "freshclam failed — continuing with last DB"
else
log "freshclam update completed"
fi
fi

# build find list of targets (public_html per user and direct WP dirs)
build_targets(){
local roots=("${SCAN_ROOTS[@]}")
local targets=()
for r in "${roots[@]}"; do
# public_html users
while IFS= read -r -d $'\0' d; do
targets+=("$d")
done &lt; &lt;(find "$r" -maxdepth 3 -type d -name public_html -print0 2>/dev/null || true)

# common WP locations (fallback)
while IFS= read -r -d $'\0' d; do
targets+=("$d")
done &lt; &lt;(find "$r" -maxdepth 4 -type d \( -name wp-content -o -name public_html -o -name html -o -name www \) -print0 2>/dev/null || true)
done

# dedupe
printf "%s\n" "${targets[@]}" | awk '!seen[$0]++'
}

# build exclude args
build_exclude_args(){
local a=()
for e in "${EXCLUDE_DIRS[@]}"; do
a+=(--exclude-dir="$e")
done
printf "%s\n" "${a[@]}"
}

# scan a single target (safe)
scan_target(){
local target="$1"
local log="$LOG_FILE"
local quar="$QUAR_DIR"
local excl=()
while IFS= read -r ex; do excl+=("$ex"; done &lt; &lt;(build_exclude_args))

# use clamdscan if daemon running (faster), fallback to clamscan
if pgrep -x clamd >/dev/null 2>&1; then
# clamdscan returns 0 if no virus, 1 if virus found, >1 for errors
log "Starting clamdscan on: $target"
clamdscan --multiscan --fdpass "${excl[@]}" --move="$quar" -l "$log" -r "$target"
rc=$?
else
log "clamd not running, using clamscan on: $target"
clamscan -ri "${excl[@]}" --move="$quar" --log="$log" "$target"
rc=$?
fi

case $rc in
0) log "No infected files found in $target";;
1) log "Infected files moved to quarantine from $target";;
*) log "Scan error (rc=$rc) on $target";;
esac
return $rc
}

# main runner: parallel across targets
main(){
log "=== CLAMWP START $(date) ==="
mapfile -t targets &lt; &lt;(build_targets)
if [ ${#targets[@]} -eq 0 ]; then
log "No targets found under configured roots: ${SCAN_ROOTS[*]}"
exit 0
fi
printf "%s\n" "${targets[@]}" | xargs -I {} -P "$PARALLEL_PROCS" bash -c '"/usr/local/bin/clamwp-scan.sh" --run-target "{}"' >/dev/null 2>&1 || true
log "=== CLAMWP DONE $(date) ==="

# send email if any "FOUND" in today's log
if grep -q "FOUND" "$LOG_FILE" || grep -q "Infected files moved to quarantine" "$LOG_FILE"; then
if [ -n "$EMAIL_ALERT" ]; then
log "Sending alert email to $EMAIL_ALERT"
echo -e "ClamAV Scan Alert\n\nLog: $LOG_FILE\n\nQuarantine: $QUAR_DIR\n\nPlease review quarantined files before any deletion." | mail -s "ClamAV Alert $(hostname) $(date +%F)" "$EMAIL_ALERT"
fi
fi
}

# helper mode: invoked by xargs to run single target
if [ "${1:-}" = "--run-target" ] && [ -n "${2:-}" ]; then
scan_target "$2"
exit $?
fi

main
EOF

sudo chmod +x /usr/local/bin/clamwp-scan.sh

Notes:

  • Script uses -move to quarantine infected files. It never calls -remove.
  • Script tries clamdscan (faster) first; falls back to clamscan.
  • You must set EMAIL_ALERT to your admin inbox or leave blank.

Small helper: rotate old logs (optional)​

Add a simple rotation script if desired:

sudo tee /usr/local/bin/clamwp-logrotate.sh > /dev/null &lt;&lt;'EOF'
#!/usr/bin/env bash
LOG_DIR="/var/log/clamwp"
find "$LOG_DIR" -type f -name "clamwp-*.log" -mtime +30 -exec gzip {} \;
EOF
sudo chmod +x /usr/local/bin/clamwp-logrotate.sh

Cron once-a-week:

0 4 * * 0 /usr/local/bin/clamwp-logrotate.sh

Cron schedule examples (safe defaults)​

Add these with sudo crontab -e (root) or system crontab:

  • Daily (nightly full scan of WordPress sites)
0 3 * * * /usr/local/bin/clamwp-scan.sh >/dev/null 2>&1

  • Quick incremental (scan files modified in last 2 days)

    Create wrapper /usr/local/bin/clamwp-recent.sh:

sudo tee /usr/local/bin/clamwp-recent.sh > /dev/null &lt;&lt;'EOF'
#!/usr/bin/env bash
# scan only files modified in last MAX_AGE_DAYS (uses find + clamscan)
MAX_AGE_DAYS=2
QUAR_DIR="/var/quarantine/clamav"
LOG_FILE="/var/log/clamwp/clamwp-recent-$(date +%F).log"
mkdir -p "$(dirname "$LOG_FILE")" "$QUAR_DIR"
find /home -type f -mtime -$MAX_AGE_DAYS -print0 2>/dev/null | xargs -0 -n1 clamscan --move="$QUAR_DIR" --log="$LOG_FILE" || true
EOF
sudo chmod +x /usr/local/bin/clamwp-recent.sh

Cron (daily at 7am):

0 7 * * * /usr/local/bin/clamwp-recent.sh >/dev/null 2>&1

Quarantine review helper​

A safe helper to list quarantined files with origin, size and SHA256:

sudo tee /usr/local/bin/clamwp-quarantine-list.sh > /dev/null &lt;&lt;'EOF'
#!/usr/bin/env bash
QUAR="/var/quarantine/clamav"
printf "%-60s %-10s %-64s\n" "PATH" "SIZE" "SHA256"
find "$QUAR" -type f -print0 | while IFS= read -r -d '' f; do
printf "%-60s %-10s %-64s\n" "$f" "$(stat -c%s "$f")" "$(sha256sum "$f" | awk '{print $1}')"
done
EOF
sudo chmod +x /usr/local/bin/clamwp-quarantine-list.sh

Run:

sudo /usr/local/bin/clamwp-quarantine-list.sh | less

Quick lab — test the toolkit (safe)​

  1. Create test webshell (EICAR-like safe test):
mkdir -p /home/testuser/public_html/wp-content/uploads/test
echo '&lt;?php echo "hello"; ?>' > /home/testuser/public_html/wp-content/uploads/test/test.php

  1. Run the scan manually:
sudo /usr/local/bin/clamwp-scan.sh

  1. Check log:
sudo tail -n 80 /var/log/clamwp/clamwp-$(date +%F).log

  1. Check quarantine:
sudo ls -la /var/quarantine/clamav
sudo /usr/local/bin/clamwp-quarantine-list.sh

Expected behaviour: file moved to quarantine, log entry says FOUND or Infected files moved to quarantine. No deletions.

Safety & operational notes (must-read)​

  • Never auto-delete in production — this toolkit intentionally quarantines only. Manual review is required.
  • Keep quarantine on a different filesystem if possible to avoid accidental overwrite (e.g., /mnt/quarantine).
  • Limit access to quarantine: chmod 700 /var/quarantine/clamav and restrict sudoers who can list it.
  • Back up logs and quarantined files before any remediation.
  • Complement with WordPress hardening: block PHP in uploads, enable WP core integrity checks, use Wordfence/other scanners for overlapping detection.
  • Signature DB freshness is vital — freshclam must run often (cron runs via clamav-freshclam service).

Troubleshooting​

  • clamscan too slow → use clamdscan and ensure clamav-daemon running.
  • freshclam fails → check /etc/clamav/freshclam.conf for network/proxy, and ensure firewall allows port 80/443 egress.
  • -move permission denied → ensure clamd runs with privileges to move files or run script as root.
  • False positives → do not delete; instead quarantine and inspect; whitelist by adding path to EXCLUDE_DIRS.
  • Too many logs → enable rotation (see section 5).
  • Email not arriving → check local mailutils setup or integrate with an SMTP relay (Postfix/ssmtp/relay).

Extension ideas (safe, non-destructive)​

  • Add an audit-report generator that snapshots wp core verify-checksums and includes it with quarantine reports.
  • Integrate with Slack/Teams via webhook when quarantine entries appear (send the log excerpt, not files).
  • Add inotify watcher to run clamwp-recent.sh for uploads directory only (low-latency detection).
  • Store SHA256 of quarantined files to build a local blacklist for quick identification.

Mini-cheat sheet (commands)​

  • Update DB: sudo freshclam
  • Run single scan: sudo /usr/local/bin/clamwp-scan.sh
  • Quick recent scan: sudo /usr/local/bin/clamwp-recent.sh
  • List quarantine: sudo /usr/local/bin/clamwp-quarantine-list.sh
  • Check logs: sudo tail -n 200 /var/log/clamwp/clamwp-$(date +%F).log
  • Use clamd manually: sudo clamdscan -r /home/user/public_html

Mini-quiz (2 questions)​

  1. What flag does ClamAV use to move infected files into a quarantine directory? (easy)
    • Answer: -move=/path/to/quarantine
  2. Why do we prefer clamdscan over clamscan on large servers? (medium)
    • Answer: clamdscan uses the clamav daemon (clamd) which loads the virus DB once and services scans in memory — far faster and lower CPU overhead than repeatedly starting clamscan.

Final checklist (before enabling cron)​

  • QUAR_DIR exists and is chmod 700
  • LOG_DIR exists and ownership/permissions correct
  • EMAIL_ALERT set to an address you monitor (or blank to disable)
  • Test scan executed and quarantine verified manually
  • Confirm clamav-daemon runs for better performance (optional)
  • Cron entries added to root crontab or system crontab

If you want, I can now:

  • produce the same toolkit but with systemd timer unit instead of cron, or
  • add a Slack notification snippet for alerts, or
  • create the incident response checklist to pair with this toolkit (you previously declined — I will not continue unless you ask).

Done — B1 Safe Mode toolkit fully delivered.